// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from "vscode";
import * as Path from "path";
import * as Fs from "fs";
import { TreeItem } from "vscode";
import { getChapter, getContent, search } from "./crawl";

const localNovelsPath = `D:\\frontpro\\vscodego\\storyvs`;

export interface NovelItem {
	name: string;
	path: string;
	isDirectory: boolean;
	type: string;
}

class NovelTreeItem extends TreeItem {
	constructor(info: NovelItem) {
		super(`${info.name}`);

		const tips = [`名称:　${info.name}`];
		// tooltip是悬浮的条提示
		this.tooltip = tips.join("\r\n");
		// 我们设置一下点击该行的命令，并且传参进去
		this.command = {
			command: "openSelectedNovel",
			title: "打开该小说",
			arguments: [{ name: info.name, path: info.path }],
		};
	}
}

function getLocalBooks(): Promise<NovelItem[]> {
	const files = Fs.readdirSync(localNovelsPath);
	const localnovellist: NovelItem[] = [];
	files.forEach((file: string) => {
		const extname = Path.extname(file).substr(1);
		if (extname === "txt") {
			const name = Path.basename(file, ".txt");
			const path = Path.join(localNovelsPath, file);
			localnovellist.push({
				path,
				name,
				isDirectory: false,
				type: "local",
			});
		}
	});
	return Promise.resolve(localnovellist);
}

export default class OnlineTreeItem extends TreeItem {
	constructor(info: NovelItem) {
		super(`${info.name}`);

		const tips = [`名称:　${info.name}`];

		this.tooltip = tips.join("\r\n");
		// 根据isDirectory属性判断是不是可折叠的组
		this.collapsibleState = info.isDirectory
			? vscode.TreeItemCollapsibleState.Collapsed
			: vscode.TreeItemCollapsibleState.None;
		// 这里命令也换了一个，换成openOnlineNovel（注意注册一下）
		this.command = info.isDirectory
			? undefined
			: {
					command: "openOnlineNovel",
					title: "打开该网络小说",
					arguments: [{ name: info.name, path: info.path }],
			  };
	}
	contextValue = "online";
}
class Provider implements vscode.TreeDataProvider<NovelItem> {
	// 发布订阅的事件
	public refreshEvent: vscode.EventEmitter<NovelItem | null> = new vscode.EventEmitter<NovelItem | null>();
	// 挂到该方法上实现刷新
	onDidChangeTreeData: vscode.Event<NovelItem | null> = this.refreshEvent
		.event;

	// 判断列表是本地还是在线
	public isOnline = false;

	public treeNode: NovelItem[] = [];

	constructor() {
		// 默认列表上先加载本地
		getLocalBooks().then((res) => {
			this.treeNode = res;
		});
	}
	// 封装一个本地和在线的切换方法
	refresh(isOnline: boolean) {
		this.isOnline = isOnline;
		this.refreshEvent.fire(null);
	}
	// 根据本地还是在线会加载不同的列表项
	getTreeItem(info: NovelItem): NovelTreeItem {
		if (this.isOnline) {
			return new OnlineTreeItem(info);
		}

		return new NovelTreeItem(info);
	}
	// 现在把列表每项的数据放在treenode上，除了在线小说展开章节的情况
	async getChildren(element?: NovelItem | undefined): Promise<NovelItem[]> {
		if (element) {
			return await getChapter(element.path);
		}
		return this.treeNode;
	}
}

export const searchOnline = async function (provider: Provider) {
	const msg = await vscode.window.showInputBox({
		password: false,
		ignoreFocusOut: false,
		placeHolder: "请输入小说的名字",
		prompt: "",
	});
	if (msg) {
		provider.treeNode = await search(msg);
		provider.refresh(true);
	}
};

class StatusBar {
	private statusBar: vscode.StatusBarItem | undefined;
	constructor() {
		this.statusBar = vscode.window.createStatusBarItem(
			vscode.StatusBarAlignment.Right
		);
		this.statusBar.text = "yehuozhili";
		this.statusBar.show();
	}
	set(val: string) {
		if (this.statusBar) {
			this.statusBar.text = val;
		}
	}
	dispose() {
		if (this.statusBar) {
			this.statusBar.dispose();
		}
	}
}

export function activate(context: vscode.ExtensionContext) {
	const progressSetting: Record<
		string,
		any
	> = vscode.workspace.getConfiguration().get("novel.progress", {});

	const op = vscode.commands.registerCommand("openSelectedNovel", (args) => {
		vscode.commands.executeCommand(
			"vscode.open",
			vscode.Uri.file(args.path)
		);
	});
	const provider = new Provider();
	const search = vscode.commands.registerCommand(
		"searchOnlineNovel",
		async function () {
			searchOnline(provider);
		}
	);
	const oponline = vscode.commands.registerCommand(
		"openOnlineNovel",
		async function (args) {
			const panel = vscode.window.createWebviewPanel(
				"novelReadWebview",
				args.name,
				vscode.ViewColumn.One,
				{
					enableScripts: true,
					retainContextWhenHidden: true,
				}
			);
			let status: StatusBar;
			panel.onDidChangeViewState((e) => {
				const active = e.webviewPanel.active;
				if (active) {
					status = new StatusBar();
				} else {
					if (status) {
						status.dispose();
					}
				}
			});

			const handleMessage = (message: {
				command: string;
				progress: number;
			}) => {
				progressSetting[args.name] = message.progress;
				if (status) {
					status.set((message.progress * 100).toFixed(2) + "%");
				}
				switch (message.command) {
					case "updateProgress":
						return vscode.workspace
							.getConfiguration()
							.update("novel.progress", progressSetting, true);
				}
			};

			const content = await getContent(args.path);
			panel.webview.html = `<html><script>
			const vscode = acquireVsCodeApi();
			setInterval(() => {
				vscode.postMessage({
					command: 'updateProgress',
					progress: window.scrollY / document.body.scrollHeight
				})
			}, 1000);  
			window.addEventListener('message', event => {
				const message = event.data; 
				switch (message.command) {
					case 'goProgress':
						window.scrollTo(0, document.body.scrollHeight * message.progress);
						break;
				}
			});
		</script><body>${content}</body></html>`;

			panel.webview.onDidReceiveMessage(
				handleMessage,
				undefined,
				context.subscriptions
			);
			panel.webview.postMessage({
				command: "goProgress",
				progress: progressSetting[args.name],
			});

			panel.onDidDispose((e) => {
				status.dispose();
			});
		}
	);

	const dis = vscode.window.registerTreeDataProvider("myread-list", provider);
	context.subscriptions.push(dis);
	context.subscriptions.push(op);
	context.subscriptions.push(search);
	context.subscriptions.push(oponline);
}

// this method is called when your extension is deactivated
export function deactivate() {}
